package service

import (
	"comm/dto"
	"comm/entity"
	"comm/qto"
	"core/coreqto"
	"core/coreservice"
	"core/corestruct"
	"core/datetime"
	"core/id"
	"core/mongo"
	"core/myerrors"
	"core/redis"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/todocoder/go-stream/stream"
	"go.mongodb.org/mongo-driver/bson"
)

const (
	DevicePrefix = "Device:"
)

type mainService struct {
}

// Page 设备分页
func (p *mainService) Page(mm *qto.CommDeviceQto, ctx *corestruct.HttpContext) (*corestruct.Page[dto.CommDeviceDto], error) {
	var db = ctx.DB

	db = db.Model(&entity.CommDevice{}).
		Select("CommDevice.*,port.name as comm_port_name,port.keep_alive as keep_alive,proxy.name as comm_proxy_name")
	if mm.Id == 0 && mm.CommPortId > 0 {
		db = db.Joins("inner join commport port on CommDevice.comm_port_id=port.id and port.id=?", mm.CommPortId)
	} else {
		db = db.Joins("inner join commport port on CommDevice.comm_port_id=port.id ", "")
	}

	if mm.Id == 0 && mm.CommProxyId > 0 {
		db = db.Joins("inner join commproxy proxy on CommDevice.comm_proxy_id=proxy.id and proxy.id=?", mm.CommProxyId)
	} else {
		db = db.Joins("inner join commproxy proxy on CommDevice.comm_proxy_id=proxy.id ", "")
	}

	if mm.Id == 0 && mm.CommDealId > 0 {
		db = db.Joins("inner join commdeal deal on CommDevice.comm_deal_id=deal.id and deal.id=?", mm.CommDealId)
	} else {
		db = db.Joins("inner join commdeal deal on CommDevice.comm_deal_id=deal.id ", "")
	}

	if mm.Id > 0 {
		db = db.Where("CommDevice.id=?", mm.Id)
	} else {
		if "" != mm.PhysicalState {
			db = db.Where("CommDevice.physical_state=?", mm.PhysicalState)
		}
		if "" != mm.LogicState {
			db = db.Where("CommDevice.logic_state=?", mm.LogicState)
		}
		if "" != mm.Key {
			var likeV = "%" + mm.Key + "%"
			db = db.Where("CommDevice.sid like  ?", likeV)
		}
	}
	var svr = &coreservice.PageService[dto.CommDeviceDto]{}
	r, err := svr.Page(&mm.BasePageQto, ctx, db)
	if err != nil {
		return nil, myerrors.NewByErr(err)
	}
	for index, v := range r.Records {
		if v.KeepAlive {

		} else {
			r.Records[index].PhysicalState = "--"
		}
	}
	return r, nil
}

// Detail 设备详情
func (p *mainService) Detail(mm *corestruct.IdModel, ctx *corestruct.HttpContext) (*dto.CommDeviceDto, error) {
	var qm = &qto.CommDeviceQto{}
	qm.Id = mm.Id
	var pgdata, err = p.Page(qm, ctx)
	if err != nil {
		return nil, err
	}
	if pgdata.TotalRow == 0 {
		return nil, nil
	}
	return &pgdata.Records[0], nil

}

// FindPropCust 设备属性数
func (p *mainService) FindPropCust(mdev *dto.StdPkgDeviceMongo, propId string) *dto.PropCustom {
	for index, v := range mdev.PropCustoms {
		if v.Id == propId {
			var v2 = mdev.PropCustoms[index]
			return &v2
		}
	}
	return nil
}

// FindPropValue 设备属性数
func (p *mainService) FindPropValue(mdev *dto.StdPkgDeviceMongo, propId string) *dto.PropValue {
	for index, v := range mdev.PropValues {
		if v.Id == propId {
			var v2 = mdev.PropValues[index]
			return &v2
		}
	}
	return nil
}

func (p *mainService) findAllDevices(sid string) ([]dto.StdPkgDeviceMongo, error) {
	var r = make([]dto.StdPkgDeviceMongo, 0)
	var prefix = DevicePrefix + sid + "*"
	var dids = redis.Scan(prefix)
	var sr = stream.Of(dids...).Sorted(func(a, b string) bool { return a < b })
	for _, v := range sr.ToSlice() {
		if !strings.HasPrefix(v, prefix) {
			continue
		}
		var m = &dto.StdPkgDeviceMongo{}
		err := redis.RedisGetStruct(v, m)
		if err != nil {
			return nil, err

		}
		r = append(r, *m)
	}
	return r, nil
}

// PropTree 设备属性数
func (p *mainService) PropTree(mm *corestruct.IdModel, ctx *corestruct.HttpContext) (*[]dto.PropValueTreeDto, error) {
	var r = make([]dto.PropValueTreeDto, 0)

	var db = ctx.DB
	var mdevice = &entity.CommDevice{Id: mm.Id}
	var tx = db.Model(mdevice).
		Select("sid").
		Find(mdevice)
	if tx.Error != nil {
		return nil, tx.Error
	}

	var devices, err = p.findAllDevices(mdevice.Sid)

	if err != nil {
		return nil, err
	}

	for _, mdev := range devices {
		var tndev = &dto.PropValueTreeDto{
			Id:       mdev.Id,
			Sid:      mdev.Sid,
			Did:      mdev.Did,
			Pid:      "",
			Name:     mdev.Name,
			Lx:       "Dev",
			Type:     0,
			Scope:    "",
			Unit:     "",
			Fv:       0,
			Sv:       "",
			State:    "",
			CrtDt:    mdev.CrtDt,
			Children: nil,
		}
		for _, mprop := range mdev.Props {
			if tndev.Children == nil {
				var child = make([]dto.PropValueTreeDto, 0)
				tndev.Children = &child
			}
			var tnprop = &dto.PropValueTreeDto{
				Id:       fmt.Sprintf("%v*%v", tndev.Id, mprop.Id),
				Sid:      mdev.Sid,
				Did:      mdev.Did,
				Pid:      mprop.Id,
				Name:     mprop.Name,
				Lx:       "Prop",
				Type:     mprop.Type,
				Scope:    mprop.Scope,
				Unit:     mprop.Unit,
				Fv:       0,
				Sv:       "",
				State:    "",
				CrtDt:    "",
				Children: nil,
			}
			var mpv = p.FindPropValue(&mdev, mprop.Id)
			if mpv != nil {
				tnprop.Fv = mpv.Fv
				tnprop.Sv = mpv.Sv
				tnprop.State = mpv.State
				tnprop.CrtDt = mpv.CrtDt
			}
			var mpc = p.FindPropCust(&mdev, mprop.Id)
			if mpc != nil {
				tnprop.Name = mpc.Name
				tnprop.Scope = mpc.Scope
				tnprop.Unit = mprop.Unit
			}
			*tndev.Children = append(*tndev.Children, *tnprop)
		}
		r = append(r, *tndev)
	}
	return &r, nil
}

// PropQst 设备属性趋势图
func (p *mainService) PropValueList(mm *coreqto.BasePageDtQto, ctx *corestruct.HttpContext) (*[]dto.StdPkgPropValueHis, error) {
	var filter = bson.M{
		"fullId": mm.BasePageQto.Key,
	}

	var dtb, err = mm.GetDtb()
	if err != nil {
		return nil, err
	}
	dte, err := mm.GetDte()
	if err != nil {
		return nil, err
	}
	var pgsvr = &mongo.ListDtService[dto.StdPkgPropValueHis]{
		ColBaseName: "StdPkgPropValue",
		Filer:       filter,
		Dtb:         *dtb,
		Dte:         *dte,
	}

	r, err := pgsvr.Query()
	if err != nil {
		return nil, err
	}
	for index, v := range *r {
		var dt = id.GetDateById(v.Id)
		((*r)[index]).CrtDt = datetime.FormatDateTime(dt)

	}
	return r, nil
}

// PropQst 设备属性趋势图
func (p *mainService) PropValuePage(mm *coreqto.BasePageDtQto, ctx *corestruct.HttpContext) (*corestruct.Page[dto.StdPkgPropValueHis], error) {
	var filter = bson.M{
		"fullId": mm.BasePageQto.Key,
	}

	var dtb, err = mm.GetDtb()
	if err != nil {
		return nil, err
	}
	dte, err := mm.GetDte()
	if err != nil {
		return nil, err
	}
	var pgsvr = &mongo.PageDtService[dto.StdPkgPropValueHis]{
		ColBaseName: "StdPkgPropValue",
		Filer:       filter,
		Dtb:         *dtb,
		Dte:         *dte,
		PageNo:      mm.Page,
		PageSize:    mm.PageSize,
	}

	r, err := pgsvr.Page()
	if err != nil {
		return nil, err
	}
	for index, v := range r.Records {
		var dt = id.GetDateById(v.Id)
		r.Records[index].CrtDt = datetime.FormatDateTime(dt)

	}
	return r, nil
}

// PageOnline 上下行分页
func (p *mainService) PageOnline(mm *coreqto.BasePageDtQto, ctx *corestruct.HttpContext) (*corestruct.Page[dto.CommDeviceOnlineDto], error) {
	var tx = ctx.DB

	tx = tx.Model(&dto.CommDeviceOnlineDto{}).
		Where("comm_device_id=?", mm.Id)

	var dtb, _ = mm.GetDtb()
	if dtb != nil {
		tx = tx.Where("online_dt>=?", dtb)
	}

	var dte, _ = mm.GetDte()
	if dte != nil {
		tx = tx.Where("off_dt<?", dte)
	}

	var svr = &coreservice.PageService[dto.CommDeviceOnlineDto]{}
	r, err := svr.Page(&mm.BasePageQto, ctx, tx)
	if err != nil {
		return nil, myerrors.NewByErr(err)
	}
	for index, _ := range r.Records {
		v := &r.Records[index]
		if "" == v.OffDt {
			OnlineDt, _ := datetime.ParseDateTime(v.OnlineDt)
			v.Seconds = int(time.Since(OnlineDt).Seconds())
		}
		if v.Seconds < 60 {
			v.Sseconds = strconv.Itoa(v.Seconds) + "秒"
		} else if v.Seconds < 3600 {
			v.Sseconds = strconv.Itoa(v.Seconds/60) + "分钟"
		} else {
			v.Sseconds = strconv.Itoa(v.Seconds/3600) + "小时" + strconv.Itoa((v.Seconds%3600)/60) + "分钟"
		}
	}
	return r, nil
}

var (
	MainService = &mainService{}
)
